#include <setjmp.h>
#include <assert.h>
#include "translate_address.hh"
#include <signal.h>
#include "sync_queue.hh"


class Sync_queue;

class uThread {
public:
	enum thread_state {
		RUNNING,
		READY,
		SUSPENDED,
	};

private:
	sigjmp_buf bookmark;
	int tid;
	char *stack;
	thread_state state;
	int wakeup_time; //stores the time we have to wake up(might need to change this into a struct)
	Sync_queue* sync_on;
	
	//we don't want anybody to be able to copy this thing.
	uThread operator=(const uThread& other) { assert(0); return NULL; };
	uThread(const uThread& other) { assert(0); };
public:
	
	//make the uThread for a thread with the default stack and no entrance function(thread0)
	uThread(int id) : tid(id), stack(NULL), state(READY), sync_on(NULL) {
	}

	virtual ~uThread() {
		if(stack!=NULL)
			delete [] stack;
	}

	//make the uThread for a thread with a custom stack and a custom function(all other threads)
	uThread(int id, void (*threadFunc)(void) ) : tid(id), stack(new char[STACK_SIZE]), state(READY), sync_on(NULL) {
		address_t sp, pc;
		sp = (address_t)stack + STACK_SIZE - sizeof(address_t);
		pc = (address_t)threadFunc;
		
		
		sigsetjmp(bookmark,1);
		(bookmark->__jmpbuf)[JB_SP] = translate_address(sp);
		(bookmark->__jmpbuf)[JB_PC] = translate_address(pc);
		sigemptyset(&bookmark->__saved_mask);
	}

	int get_id() const {
		return tid;
	};
	
	/**
	 * The smaller thread is the one that's not suspended. Otherwise it's according to ID
	 */
	bool operator<(const uThread& other) const {
		if(this->suspended() == other.suspended())
			return this->get_id() > other.get_id();
		else if(this->suspended())
			return false;
		else if(other.suspended())
			return true;
		else
			assert(false);
	};
	
	
	// saves a bookmark, returns 0 if the bookmark was saved and 1 if we just returned here.
	int set_bookmark() {
		return sigsetjmp(bookmark, 1);
	}
	
	// runs this thread(basically just a siglongjump)
	void run_thread() {
		siglongjmp(bookmark, 1);
	}
	
	
	thread_state get_state() const {
		return this->state;
	}
	
	void set_state(thread_state newstate) {
		state=newstate;
	}
	
	//return the time until we have to wakeup
	int get_time_until_wakeup() {
		return 0; //TODO: implement this
	}

	bool ready() const {
		return this->get_state() == READY;
	}
	bool running() const {
		return this->get_state() == RUNNING;
	}
	bool suspended() const {
		return this->get_state() == SUSPENDED;
	}
	
	void set_sync(Sync_queue* sync_queue) {
		sync_on = sync_queue;
	}
	Sync_queue* get_sync() {
		return sync_on;
	}
	
};

class uThreadPCompare { // simple comparison function
public:
	bool operator()(const uThread* x,const uThread* y) { 
		return ((*x)<(*y));
	};
};
